#include <iostream>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include "gedgee.h"  // 包含提供的头文件

// 全局变量防止优化
volatile uint64_t resultAccumulator = 0;
volatile float floatAccumulator = 0.0f;
volatile double doubleAccumulator = 0.0;

// 计时测试函数
void runTest(void (*testFunc)(), const char* description, uint64_t iterations = 100000000) {
    auto start = std::chrono::high_resolution_clock::now();

    for (int i = 0; i < iterations; ++i) {
        testFunc();
    }

    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();

    printf(
        "%s (%lu iterations): %08ld μs (%lf μs/op)\n",
        description, iterations, duration,
        static_cast<double>(duration) / static_cast<double>(iterations)
    );
}

using namespace gedgee;

// ================== int16_t 测试 ==================
extern "C" void test_i16() {
    vector128 vec1 = v128_fill<i16>(1);
    vector128 vec2 = v128_fill<i16>(2);

    vec2 = v128_add<i16>(vec1, vec2);
    vec2 = v128_sub<i16>(vec1, vec2);
    vec2 = v128_mul<i16>(vec1, vec2);
    vec2 = v128_div<i16>(vec1, vec2);
    vec2 = v128_max<i16>(vec1, vec2);
    vec2 = v128_min<i16>(vec1, vec2);
    vec2 = v128_and<i16>(vec1, vec2);
    vec2 = v128_or<i16>(vec1, vec2);
    vec2 = v128_xor<i16>(vec1, vec2);
    vec2 = v128_andnot<i16>(vec1, vec2);
    vec2 = v128_sll<i16>(vec1, 1);
    vec2 = v128_sra<i16>(vec1, 1);
    vec2 = v128_abs<i16>(vec1);
    vec2 = v128_neg<i16>(vec1);
}

// ================== int32_t 测试 ==================
extern "C" void test_i32() {
    vector128 vec1 = v128_fill<i32>(1);
    vector128 vec2 = v128_fill<i32>(2);

    vec2 = v128_add<i32>(vec1, vec2);
    vec2 = v128_sub<i32>(vec1, vec2);
    vec2 = v128_mul<i32>(vec1, vec2);
    vec2 = v128_div<i32>(vec1, vec2);
    vec2 = v128_max<i32>(vec1, vec2);
    vec2 = v128_min<i32>(vec1, vec2);
    vec2 = v128_and<i32>(vec1, vec2);
    vec2 = v128_or<i32>(vec1, vec2);
    vec2 = v128_xor<i32>(vec1, vec2);
    vec2 = v128_andnot<i32>(vec1, vec2);
    vec2 = v128_sll<i32>(vec1, 1);
    vec2 = v128_sra<i32>(vec1, 1);
    vec2 = v128_abs<i32>(vec1);
    vec2 = v128_neg<i32>(vec1);
}

// ================== float32 测试 ==================
extern "C" void test_f32() {
    vector128 vec1 = v128_fill<f32>(1);
    vector128 vec2 = v128_fill<f32>(2);

    vec2 = v128_add<f32>(vec1, vec2);
    vec2 = v128_sub<f32>(vec1, vec2);
    vec2 = v128_mul<f32>(vec1, vec2);
    vec2 = v128_div<f32>(vec1, vec2);
    vec2 = v128_max<f32>(vec1, vec2);
    vec2 = v128_min<f32>(vec1, vec2);
    vec2 = v128_abs<f32>(vec1);
    vec2 = v128_neg<f32>(vec1);
    vec2 = v128_sqrt<f32>(vec2);
    vec2 = v128_rsqrt<f32>(vec2);
    vec2 = v128_rcp<f32>(vec2);
    vec2 = v128_round<f32>(vec2);
}

// ================== float64 测试 ==================
extern "C" void test_f64() {
    vector128 vec1 = v128_fill<f64>(1);
    vector128 vec2 = v128_fill<f64>(2);

    vec2 = v128_add<f64>(vec1, vec2);
    vec2 = v128_sub<f64>(vec1, vec2);
    vec2 = v128_mul<f64>(vec1, vec2);
    vec2 = v128_div<f64>(vec1, vec2);
    vec2 = v128_max<f64>(vec1, vec2);
    vec2 = v128_min<f64>(vec1, vec2);
    vec2 = v128_abs<f64>(vec1);
    vec2 = v128_neg<f64>(vec1);
    vec2 = v128_sqrt<f64>(vec2);
    vec2 = v128_rsqrt<f64>(vec2);
    vec2 = v128_rcp<f64>(vec2);
    vec2 = v128_round<f64>(vec2);
}

void test_abs() {
    vector128 vec = v128_fill<f64>(-2.5);

    vec = v128_abs<f64>(vec);
}

int main() {
    std::cout << "Starting ";
    std::cout <<
    #ifdef GGE_NOSIMD
        "NOSIMD"
    #else
        "SIMD"
    #endif
    ;
    std::cout << " performance tests...\n\n";

    // 运行所有测试
    runTest(test_i16, "int16_t operations");
    runTest(test_i32, "int32_t operations");
    runTest(test_f32, "float32 operations");
    runTest(test_f64, "float64 operations");
    runTest(test_abs, "float64 abs operations");

    // 使用累计结果防止优化
    std::cout << "\nAccumulated results (anti-optimization):\n";
    std::cout << "int: " << resultAccumulator << "\n";
    std::cout << "float: " << floatAccumulator << "\n";
    std::cout << "double: " << doubleAccumulator << "\n";

    return 0;
}